#ifndef UTIL_H
#define UTIL_H
/*
 * Copyright (C) 2011 Alexey Solomin, a.rainman on gmail point com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "platform.h"

#include "lcd.h"
#include <stdio.h>
#include <cstdio>
//==============================================================================
#include "../revision.h"
//==============================================================================

//#define SYSTEM_DEBUG

//==============================================================================

#define SETTINGS(name, dev, min, max, def, type)\
  static CONST type dev##name##Min = min;\
  static CONST type dev##name##Max = max;\
  static CONST type dev##name##Default = def


#define VER_MIN_S(value, dev)\
  if (value < dev##value##Min)\
    value = dev##value##Default


#define VER_MIN(value)\
  if (value < value##Min)\
    value = value##Default


#define VER_MAX_S(value, dev)\
  if (value > dev##value##Max)\
    value = dev##value##Default


#define VER_MAX(value)\
  if (value > value##Max)\
    value = value##Default


#define VERIFI_S(value, dev)\
  if (value < dev##value##Min || value > dev##value##Max)\
    value = dev##value##Default


#define VERIFI(value)\
  if (value < value##Min || value > value##Max)\
    value = value##Default


#define VER_MIN_EXCL_ZERO(value)\
  if (value != 0 && value < value##Min)\
    value = value##Default


// TODO
#define GETSET(type, name, name2)\
  private: type name;\
  public: /*TODO TypeTraits<type>::ParameterType*/ type get##name2() const { return name; }\
  void set##name2(/*TODO TypeTraits<type>::ParameterType*/ type a##name2) { name = a##name2; }


#define GETSETBASE(type, name, name2)\
  protected: type name;\
  public: /*TODO TypeTraits<type>::ParameterType*/ type get##name2() const { return name; }\
  void set##name2(/*TODO TypeTraits<type>::ParameterType*/ type a##name2) { name = a##name2; }

//==============================================================================
template<typename T, typename T1, typename T2>
void lcdLog(const T* code,
            const T1* data,  const size_t len,
            const T2* data2, const size_t len2)
{
  lcd.clear();
  lcd.print(code);
  if (len)
  {
    lcd.print(", size=");
    lcd.print_int_zzz(len);
  }
  lcd.goto2stLine();
  if (data)
  {
    if (len)
      lcd.print(data, len);
    else
      lcd.print(data);
  }
  if (data2)
  {
    if (len2)
      lcd.print(data2, len2);
    else
      lcd.print(data2);
  }
  __delay_cycles(20000000);
}
//==============================================================================
inline void lcdLog(const char* str1, const char* str2, const char* str22)
{
  lcdLog(str1, str2, 0, str22, 0);
}
//==============================================================================
inline void lcdLog(const char* str1, const char* str2)
{
  lcdLog(str1, str2, 0, (const char *)NULL, 0);
}
//==============================================================================
inline void lcdLog(const char* str1, const char* str2, int num)
{
  static CONST char formatd[] = "%d";
  char buf[5];
  sprintf_P(buf, formatd, num);
  lcdLog(str1, str2, 0, buf, 0);
}
//==============================================================================
template<typename T>
void DebugLog(const char* code, const T* data, const size_t len)
{
#ifdef SYSTEM_DEBUG
  lcdLog(code, data, len, (const char *)NULL, 0);
#endif // SYSTEM_DEBUG
}
//==============================================================================
#ifdef SYSTEM_DEBUG

#define dcassert(exp) \
  if (!(exp))\
    lcdLog("Assertion hit in " #exp "", __FILE__, __LINE__)

#else

#define dcassert(exp)

#endif //SYSTEM_DEBUG

//==============================================================================
template<typename T>
void DebugLog(const char* str1, const T* str2)
{
#ifdef SYSTEM_DEBUG
  DebugLog(str1, str2, 0);
#endif // SYSTEM_DEBUG
}
//==============================================================================
inline void DebugLog(const char* code)
{
#ifdef SYSTEM_DEBUG
  DebugLog(code, (int*)NULL);
#endif // SYSTEM_DEBUG
}
//==============================================================================
inline void DebugLog(const char* code, const int val)
{
#ifdef SYSTEM_DEBUG
  lcd.clear();
  lcd.print(code);
  lcd.print("=");
  lcd.print_int_zzz(val);
  __delay_cycles(10000000);
#endif // SYSTEM_DEBUG
}
//==============================================================================
inline void printVersion()
{
  lcd.print("Ver." A_REVISION_NUM_STR);
  lcd.goto2stLine();
  lcd.print(__DATE__ " " __TIME__);
}
//==============================================================================
#endif // UTIL_H